/*
 * yauosk - Yet Another Useless Operating System Kernel
 *
 * Copyright (c) 2009-2010 Matteo Cicuttin
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 * derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Very simple printf.
 */

#include <arch/machine.h>
#include <sys/types.h>

static void
printnum(int n, int base, int sf)
{
	char buf[32];
	char digits[] = "0123456789ABCDEF";
	int i = 0, neg = 0;
	
	uint nn;
	
	if (sf && n < 0)
	{
		neg = 1;
		nn = -n;
	}
	else
	{
		nn = n;
	}
	
	do {
		buf[i++] = digits[nn%base];
	} while ( (nn/=base) != 0 );
	
	if (neg) buf[i++] = '-';
	
	while (i--)
		PUTC(buf[i]);
}

int
printf(char *fmt, ...)
{
	int i, c, state;
	char *s;
	uint *va = (uint *)(void *)&fmt+1;
	
	state = 0;
	i = 0;
	
	for(i = 0; fmt[i]; i++)
	{
		c = fmt[i];
		if (state == 0)
		{
			if (c == '%')
				state = '%';
			else
				PUTC(c);
		}
		else if (state == '%')
		{
			switch (c)
			{
				case 'd':
					printnum(*va, 10, 1);
					va++;
					break;
					
				case 'x':
					printnum(*va, 16, 0);
					va++;
					break;
					
				case 'p':
					PUTC('0');
					PUTC('x');
					printnum(*va, 16, 0);
					va++;
					break;
				
				case 's':
					s = (char *) *va;
					va++;
					while(*s)
						PUTC(*s++);
					break;
					
				case 'c':
					PUTC(*va);
					*va++;
					break;
					
				case '%':
					PUTC(c);
					break;
					
				default:
					PUTC('%');
					PUTC('c');
					break;
			}
			
			state = 0;
		}
	}	
	
	return 0;
}
